home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 22
/
Cream of the Crop 22.iso
/
doom
/
quake2.zip
/
TF1_2SRC.ZIP
/
QUAKE
/
FORTRESS
/
SOURCE
/
TFORT.QC
< prev
next >
Wrap
Text File
|
1996-09-10
|
65KB
|
2,365 lines
/*
TeamFortress 1.2 - 7/9/96
Robin Walker, John Cook, Ian Caughley.
Functions specific to the TeamFortress QuakeC patch.
*/
// Function Prototypes
void() GrenadeExplode;
void() spike_touch;
void() bound_other_ammo;
// Help Functions
void() TeamFortress_MOTD;
void() TeamFortress_HelpIndex;
void() TeamFortress_HelpWeapon;
void() TeamFortress_HelpClass;
void() TeamFortress_HelpItem;
void() TeamFortress_HelpGeneral;
void() TeamFortress_HelpPreImp;
void() TeamFortress_HelpShowPreImp;
// Multiskin Functions
void(float skinno) Multiskin_SetSkin;
// Team Functions
float(float tno) TeamFortress_TeamGetColor;
void(float tno) TeamFortress_TeamSetColor;
float() TeamFortress_TeamPutPlayerInTeam;
// Impulse Functions
void() TeamFortress_ChangeClass;
void() TeamFortress_Inventory;
void() TeamFortress_ShowTF;
void() TeamFortress_PrimeGrenade;
void() TeamFortress_ThrowGrenade;
void() TeamFortress_DetonatePipebombs;
// Pre-Impulse Functions
void(float tflag) TeamFortress_Toggle;
void(float scanrange) TeamFortress_Scan;
void(float timer) TeamFortress_SetDetpack;
void(float skinno) TeamFortress_Multiskin;
// Player Class Handling Functions
void() TeamFortress_SetHealth;
void() TeamFortress_SetEquipment;
void() TeamFortress_SetSpeed;
void() TeamFortress_SetSkin;
void() TeamFortress_PrintClassName;
void() TeamFortress_RemoveTimers;
void() TeamFortress_CheckClassStats;
float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo;
float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon;
float(entity Retriever, entity Armor) TeamFortress_CanGetArmor;
float(entity Retriever, entity Items) TeamFortress_AddBackpackItems;
// Weapon Handling Functions
void() TeamFortress_SniperWeapon;
void() TeamFortress_ExplodePerson;
void() NormalGrenadeTouch;
void() NormalGrenadeExplode;
void() ConcussionGrenadeTouch;
void() ConcussionGrenadeExplode;
void() ConcussionGrenadeTimer;
void() NailGrenadeTouch;
void() NailGrenadeExplode;
void() NailGrenadeNailEm;
void() NailGrenadeLaunchNail;
void() MirvGrenadeTouch;
void() MirvGrenadeExplode;
void(vector org, entity shooter) MirvGrenadeLaunch;
void() PipebombTouch;
// Item Handling Functions
void() TeamFortress_DetpackSet;
void() TeamFortress_DetpackExplode;
void() TeamFortress_DetpackTouch;
void() TeamFortress_DetpackCountDown;
// Utility Functions
void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce;
entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan;
void(string halias, float himpulse1, float himpulse2) TeamFortress_Alias;
// Cyclic Event Functions
void() TeamFortress_Regenerate;
void() TeamFortress_CheckforCheats;
void(entity Item, entity AP, float method) tfgoalitem_RemoveFromAP;
//=========================================================================
// IMPULSE FUNCTIONS
//=========================================================================
//=========================================================================
// Impulse function which Toggles Game Settings
void(float tflag) TeamFortress_Toggle =
{
local entity e,bak;
local string db;
// prevent pre-impulse from triggering anything else
self.impulse = 0;
self.last_impulse = 0;
// Classkin/Multiskin
if (tflag == TF_TOGGLE_SKIN)
{
if (toggleflags & TFLAG_SKIN)
{
bprint("Classkin On.\n");
toggleflags = toggleflags - (toggleflags & TFLAG_SKIN);
bak = self;
// Change everyone's skins to their class
e = find(world, classname, "player");
while (e)
{
self = e;
TeamFortress_SetSkin();
e = find(e, classname, "player");
}
self = bak;
}
else
{
bprint("Multiskin On.\n");
toggleflags = (toggleflags | TFLAG_SKIN);
}
return;
}
// Class Persistence between lvls On/Off
if (tflag == TF_TOGGLE_CLASS_PERSIST)
{
if (toggleflags & TFLAG_CLASS_PERSIST)
{
bprint("Class Persistence Off.\n");
toggleflags = toggleflags - (toggleflags & TFLAG_CLASS_PERSIST);
}
else
{
bprint("Class Persistence On.\n");
toggleflags = (toggleflags | TFLAG_CLASS_PERSIST);
}
return;
}
// turn auto placement of players in team on/off
if (tflag == TF_TOGGLE_AUTOTEAM)
{
if (toggleflags & TFLAG_AUTOTEAM)
{
bprint("Auto team placement Off.\n");
toggleflags = toggleflags - (toggleflags & TFLAG_AUTOTEAM);
}
else
{
bprint("Auto team placement On.\n");
toggleflags = toggleflags | TFLAG_AUTOTEAM;
}
}
// Respawn delays Cycle
if (tflag == TF_TOGGLE_RESPAWNDELAY)
{
if ((toggleflags & TFLAG_RESPAWNDELAY) && (toggleflags & TFLAG_RESPAWNDELAY2))
{
// turn all off
bprint("Respawn Delay Off.\n");
toggleflags = toggleflags - (toggleflags & TFLAG_RESPAWNDELAY);
toggleflags = toggleflags - (toggleflags & TFLAG_RESPAWNDELAY2);
}
else if (toggleflags & TFLAG_RESPAWNDELAY)
{
// level one on, move to level two (off, on)
bprint("Respawn Delay On, ");
db = ftos(TF_RESPAWNDELAY2);
bprint(db);
bprint(" seconds.\n");
toggleflags = toggleflags | TFLAG_RESPAWNDELAY2;
toggleflags = toggleflags - TFLAG_RESPAWNDELAY;
}
else if (toggleflags & TFLAG_RESPAWNDELAY2)
{
// level two on, move to level three (both flags set)
bprint("Respawn Delay On, ");
db = ftos(TF_RESPAWNDELAY3);
bprint(db);
bprint(" seconds.\n");
toggleflags = toggleflags | TFLAG_RESPAWNDELAY | TFLAG_RESPAWNDELAY2;
}
else
{
// set to level one
bprint("Respawn Delay On, ");
db = ftos(TF_RESPAWNDELAY1);
bprint(db);
bprint(" seconds.\n");
toggleflags = toggleflags | TFLAG_RESPAWNDELAY;
toggleflags = toggleflags - (toggleflags & TFLAG_RESPAWNDELAY2);
}
}
// Cheat Checking On/Off
if (tflag == TF_TOGGLE_CHEATCHECK)
{
if (toggleflags & TFLAG_CHEATCHECK)
{
bprint("Cheat Checking Off.\n");
toggleflags = toggleflags - (toggleflags & TFLAG_CHEATCHECK);
// Remove everyone's cheattimers
e = find(world, classname, "timer");
while (e)
{
if (e.think == TeamFortress_CheckforCheats)
{
bprint("Removed cheattimer.\n");
remove(e);
e = find(world, classname, "timer");
}
else
e = find(e, classname, "timer");
}
}
else
{
bprint("Cheat Checking On.\n");
toggleflags = (toggleflags | TFLAG_CHEATCHECK);
// Create everyone's cheattimers
e = find(world, classname, "player");
while (e)
{
bak = spawn();
bak.nextthink = time + 20;
bak.think = TeamFortress_CheckforCheats;
bak.classname = "timer";
bak.owner = e;
e = find(e, classname, "player");
}
}
return;
}
// FortressMap details On/Off (see readme.txt for more info)
if (tflag == TF_TOGGLE_FORTRESSMAP)
{
if (toggleflags & TFLAG_FORTRESSMAP)
{
bprint("FortressMap Off.\n");
toggleflags = toggleflags - (toggleflags & TFLAG_FORTRESSMAP);
}
else
{
bprint("FortressMap On.\n");
toggleflags = (toggleflags | TFLAG_FORTRESSMAP);
}
return;
}
};
//=========================================================================
// Handles the Multiskin Pre-Impulse to Set Skin
void(float skinno) TeamFortress_Multiskin =
{
// prevent help pre-impulse from triggering anything else
self.impulse = 0;
self.last_impulse = 0;
Multiskin_SetSkin(skinno);
};
//=========================================================================
// Player change class function
void() TeamFortress_ChangeClass =
{
local entity spot;
cvar_set("sv_maxspeed", "600");
// Only change playerclass once - remove this if you want to change on the fly
if ( self.playerclass != PC_UNDEFINED )
return;
// players must join a team, if teamplay is on
if (teamplay && self.team_no == 0)
{
// check for auto team placement
if (toggleflags & TFLAG_AUTOTEAM)
{
// If it failed, return
if (TeamFortress_TeamPutPlayerInTeam() == FALSE)
return;
}
else
{
sprint(self, "You must join a team first. \n");
sprint(self, "use imin1, imin2, imin3, or imin4\n");
return;
}
}
self.playerclass = self.impulse - TF_CHANGEPC;
// Turn off PC_UNDEFINED's nomove and invincibility
self.takedamage = DAMAGE_AIM;
self.movetype = MOVETYPE_WALK;
// give them a model, and a new spawn point
self.solid = SOLID_SLIDEBOX;
// pausetime is set by teleporters to keep the player from moving a while
self.pausetime = 0;
spot = SelectSpawnPoint ();
self.origin = spot.origin + '0 0 1';
self.angles = spot.angles;
self.fixangle = TRUE; // turn this way immediately
setmodel (self, "progs/eyes.mdl");
modelindex_eyes = self.modelindex;
setmodel (self, "progs/player.mdl");
modelindex_player = self.modelindex;
setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
self.view_ofs = '0 0 22';
player_stand1 ();
if (deathmatch || coop)
{
makevectors(self.angles);
spawn_tfog (self.origin + v_forward*20);
}
// Display chosen class, and Tell rest of the team in the future
if ( self.playerclass == PC_RANDOM )
{
sprint(self, "Random Playerclass.\n");
self.tfstate = (self.tfstate | TFSTATE_RANDOMPC);
self.playerclass = 1 + floor(random() * (PC_RANDOM - 1));
}
TeamFortress_PrintClassName();
TeamFortress_SetEquipment();
TeamFortress_SetHealth();
TeamFortress_SetSpeed();
TeamFortress_SetSkin();
};
//=========================================================================
// Displays the player's inventory
void() TeamFortress_Inventory =
{
local entity tg;
local string ac;
local float col;
// Display Team
sprint(self, "You're in team ");
ac = ftos(self.team_no);
sprint(self, ac);
sprint(self, ", color ");
col = TeamFortress_TeamGetColor(self.team_no);
ac = ftos(col);
sprint(self, ac);
sprint(self, ".\n");
// Display Number of Grenades of each type
if (self.no_grenades_1 > 0)
{
sprint(self, "Gren.Type 1 : ");
if (self.tp_grenades_1 == GR_TYPE_NORMAL)
sprint(self, " Normal(");
if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
sprint(self, " Concussion(");
if (self.tp_grenades_1 == GR_TYPE_NAIL)
sprint(self, " Nail(");
if (self.tp_grenades_1 == GR_TYPE_MIRV)
sprint(self, " Mirv(");
ac = ftos(self.no_grenades_1);
sprint(self, ac);
sprint(self, ")\n");
}
if (self.no_grenades_2 > 0)
{
sprint(self, "Gren.Type 2 : ");
if (self.tp_grenades_2 == GR_TYPE_NORMAL)
sprint(self, " Normal(");
if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
sprint(self, " Concussion(");
if (self.tp_grenades_2 == GR_TYPE_NAIL)
sprint(self, " Nail(");
if (self.tp_grenades_2 == GR_TYPE_MIRV)
sprint(self, " Mirv(");
ac = ftos(self.no_grenades_1);
sprint(self, ac);
sprint(self, ")\n");
}
// Scanner
if (self.tf_items & NIT_SCANNER)
sprint(self, "Scanner. ");
// Medikit and ammo
if (self.secondary_items & NIT_MEDIKIT)
{
sprint(self, "Medikit (");
ac = ftos(self.ammo_medikit);
sprint(self, ac);
sprint(self,") ");
}
// Detpack
if (self.secondary_items & NIT_DETPACK)
{
if (self.ammo_detpack > 0)
{
ac = ftos(self.ammo_detpack);
sprint(self, ac);
sprint(self, " Detpack");
if (self.ammo_detpack > 1)
sprint(self, "s");
sprint(self, ". ");
}
}
// GoalItems
tg = find (world, classname, "item_tfgoal");
while (tg)
{
if (tg.owner == self)
{
sprint(self, tg.netname);
sprint(self, ". ");
}
tg = find(tg, classname, "item_tfgoal");
}
sprint(self, "\n");
};
//=========================================================================
// Displays the state of the ToggleFlags
void() TeamFortress_ShowTF =
{
local string st;
// Classkin/Multiskin
if (toggleflags & TFLAG_SKIN)
sprint(self, "Multiskin On.\n");
else
sprint(self, "Classkin On.\n");
// Class Persistence between lvls On/Off
if (toggleflags & TFLAG_CLASS_PERSIST)
sprint(self, "Class Persistence On.\n");
else
sprint(self, "Class Persistence Off.\n");
// Cheat Checking On/Off
if (toggleflags & TFLAG_CHEATCHECK)
sprint(self, "Cheat Checking On.\n");
else
sprint(self, "Cheat Checking Off.\n");
// FortressMap details On/Off (see readme.txt for more info)
if (toggleflags & TFLAG_FORTRESSMAP)
sprint(self, "FortressMap On.\n");
else
sprint(self, "FortressMap Off.\n");
// AutoTeam On/Off
if (toggleflags & TFLAG_AUTOTEAM)
sprint(self, "AutoTeam On.\n");
else
sprint(self, "AutoTeam Off.\n");
// RespawnDelay
if ((toggleflags & TFLAG_RESPAWNDELAY) && (toggleflags & TFLAG_RESPAWNDELAY2))
st = ftos(TF_RESPAWNDELAY3);
else if (toggleflags & TFLAG_RESPAWNDELAY)
st = ftos(TF_RESPAWNDELAY1);
else if (toggleflags & TFLAG_RESPAWNDELAY2)
st = ftos(TF_RESPAWNDELAY2);
else
st = "No";
sprint(self, st);
if (st != "No")
sprint(self, " second");
sprint(self, " Respawn Delay.\n");
};
//=========================================================================
// Primes a grenade of the type corresponding to the player's impulse
void() TeamFortress_PrimeGrenade =
{
local float gtype;
local string gs, ptime;
local entity tGrenade;
// If you've already primed a grenade, return
if (self.tfstate & TFSTATE_GRENPRIMED)
return;
if (self.impulse == TF_GRENADE_1)
{
gtype = self.tp_grenades_1;
if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
gs = "Concussion grenade";
else if (self.tp_grenades_1 == GR_TYPE_NAIL)
gs = "Nail grenade";
else if (self.tp_grenades_1 == GR_TYPE_MIRV)
gs = "Mirv grenade";
else
gs = "Grenade";
if (self.no_grenades_1 > 0)
{
ptime = ftos( GR_PRIMETIME );
sprint(self, gs);
sprint(self, " primed, ");
sprint(self, ptime);
sprint(self, " seconds...\n");
self.no_grenades_1 = self.no_grenades_1 - 1;
}
else
{
sprint(self, "No ");
sprint(self, gs);
sprint(self, "s left.\n");
return;
}
}
if (self.impulse == TF_GRENADE_2)
{
gtype = self.tp_grenades_2;
if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
gs = "Concussion grenade";
else if (self.tp_grenades_2 == GR_TYPE_NAIL)
gs = "Nail grenade";
else if (self.tp_grenades_2 == GR_TYPE_MIRV)
gs = "Mirv grenade";
else
gs = "Grenade";
if (self.no_grenades_2 > 0)
{
ptime = ftos( GR_PRIMETIME );
sprint(self, gs);
sprint(self, " primed, ");
sprint(self, ptime);
sprint(self, " seconds...\n");
self.no_grenades_2 = self.no_grenades_2 - 1;
}
else
{
sprint(self, "No ");
sprint(self, gs);
sprint(self, "s left.\n");
return;
}
}
self.tfstate = (self.tfstate | TFSTATE_GRENPRIMED);
tGrenade = spawn();
tGrenade.owner = self;
tGrenade.weapon = gtype;
tGrenade.classname = "timer";
tGrenade.nextthink = time + GR_PRIMETIME;
tGrenade.think = TeamFortress_ExplodePerson;
};
//=========================================================================
// Throws a currently primed grenade
void() TeamFortress_ThrowGrenade =
{
local entity missile, te;
// If no grenade is primed, return
if (!(self.tfstate & TFSTATE_GRENPRIMED))
return;
self.tfstate = self.tfstate - (self.tfstate & TFSTATE_GRENPRIMED);
sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
missile.classname = "grenade";
// set grenade speed
makevectors (self.v_angle);
if (self.v_angle_x)
missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
else
{
missile.velocity = aim(self, 10000);
missile.velocity = missile.velocity * 600;
missile.velocity_z = 200;
}
missile.avelocity = '300 300 300';
missile.angles = vectoangles(missile.velocity);
// set the grenade's alternative kill flag
missile.tfstate = missile.tfstate | TFSTATE_ALTKILL;
// Find the grenade entity
te = find(world, classname, "timer");
while ((te.owner != self) || (te.think != TeamFortress_ExplodePerson))
te = find(te, classname, "timer");
// If we haven't found the grenade, something's wrong
if (te == world)
{
dprint("Error! Grenade entity not found.\n");
return;
}
// set the grenade's thinktime to when the PRIMETIME runs out
missile.nextthink = te.nextthink;
// set the think and touches to the appropriate grenade type
if (te.weapon == GR_TYPE_NORMAL)
{
missile.touch = NormalGrenadeTouch;
missile.think = NormalGrenadeExplode;
missile.altkillweapon = AK_GRENADE;
}
if (te.weapon == GR_TYPE_CONCUSSION)
{
missile.touch = ConcussionGrenadeTouch;
missile.think = ConcussionGrenadeExplode;
}
if (te.weapon == GR_TYPE_NAIL)
{
missile.touch = NailGrenadeTouch;
missile.think = NailGrenadeExplode;
missile.altkillweapon = AK_GRENADE_NAIL;
}
if (te.weapon == GR_TYPE_MIRV)
{
missile.touch = MirvGrenadeTouch;
missile.think = MirvGrenadeExplode;
missile.altkillweapon = AK_GRENADE_MIRV;
}
setmodel (missile, "progs/grenade.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin);
// Remove primed grenade object
remove(te);
};
//=========================================================================
// PLAYER CLASS HANDLING FUNCTIONS
//=========================================================================
//=========================================================================
// Alter the player's Movement based on class
void() TeamFortress_SetSpeed =
{
local string sp;
local float tf;
stuffcmd(self,"v_idlescale 0\n");
stuffcmd(self,"cl_movespeedkey 1\n");
if ( self.playerclass == PC_SCOUT )
{
self.maxfbspeed = PC_SCOUT_MAXSPEED;
self.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED;
}
else if ( self.playerclass == PC_SNIPER )
{
self.maxfbspeed = PC_SNIPER_MAXSPEED;
self.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED;
}
else if ( self.playerclass == PC_SOLDIER )
{
self.maxfbspeed = PC_SOLDIER_MAXSPEED;
self.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED;
}
else if ( self.playerclass == PC_DEMOMAN )
{
self.maxfbspeed = PC_DEMOMAN_MAXSPEED;
self.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED;
}
else if ( self.playerclass == PC_MEDIC )
{
self.maxfbspeed = PC_MEDIC_MAXSPEED;
self.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED;
}
else if ( self.playerclass == PC_HVYWEAP )
{
self.maxfbspeed = PC_HVYWEAP_MAXSPEED;
self.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED;
}
else if ( self.playerclass == PC_UNDEFINED )
{
self.maxfbspeed = 50;
self.maxstrafespeed = 50;
self.movetype = MOVETYPE_NONE;
}
sp = ftos(self.maxfbspeed);
stuffcmd(self,"cl_backspeed ");
stuffcmd(self,sp);
stuffcmd(self,"\n");
stuffcmd(self,"cl_forwardspeed ");
stuffcmd(self,sp);
stuffcmd(self,"\n");
sp = ftos(self.maxstrafespeed);
stuffcmd(self,"cl_sidespeed ");
stuffcmd(self,sp);
stuffcmd(self,"\n");
};
//=========================================================================
// Set the max_health of a player based on his/her class
void() TeamFortress_SetHealth =
{
if ( self.playerclass == PC_SCOUT )
self.max_health = PC_SCOUT_MAXHEALTH;
else if ( self.playerclass == PC_SNIPER )
self.max_health = PC_SNIPER_MAXHEALTH;
else if ( self.playerclass == PC_SOLDIER )
self.max_health = PC_SOLDIER_MAXHEALTH;
else if ( self.playerclass == PC_DEMOMAN )
self.max_health = PC_DEMOMAN_MAXHEALTH;
else if ( self.playerclass == PC_MEDIC )
self.max_health = PC_MEDIC_MAXHEALTH;
else if ( self.playerclass == PC_HVYWEAP )
self.max_health = PC_HVYWEAP_MAXHEALTH;
else if ( self.playerclass == PC_UNDEFINED )
{
self.max_health = 1;
self.takedamage = 0; // Prevent damage to PC_UNDEFINED players
}
self.health = self.max_health;
};
//=========================================================================
// Set the skin of a player based on his/her class, if Classkin is on
void() TeamFortress_SetSkin =
{
local string st;
// If Multiskin is on, return
if (toggleflags & TFLAG_SKIN)
return;
if ( self.playerclass == PC_SCOUT )
self.skin = PC_SCOUT_SKIN;
else if ( self.playerclass == PC_SNIPER )
self.skin = PC_SNIPER_SKIN;
else if ( self.playerclass == PC_SOLDIER )
self.skin = PC_SOLDIER_SKIN;
else if ( self.playerclass == PC_DEMOMAN )
self.skin = PC_DEMOMAN_SKIN;
else if ( self.playerclass == PC_MEDIC )
self.skin = PC_MEDIC_SKIN;
else if ( self.playerclass == PC_HVYWEAP )
self.skin = PC_HVYWEAP_SKIN;
else if ( self.playerclass == PC_UNDEFINED )
self.skin = 1;
};
//=========================================================================
// Set the details of a player based on his/her class
void() TeamFortress_SetEquipment =
{
local entity te;
if (self.classname != "player")
return;
self.items = 0;
self.secondary_weapon = 0;
self.secondary_items = 0;
self.tf_items = 0;
self.tf_items_flags = 0;
self.armorclass = 0;
self.impulse = 0;
self.ammo_medikit = 0;
self.maxammo_medikit = 0;
self.ammo_detpack = 0;
self.maxammo_detpack = 0;
self.items_allowed = 0;
self.secondary_items_allowed = 0;
self.armor_allowed = 0;
self.maxarmor = 0;
self.weaponmode = 0;
self.altkillweapon = 0;
self.heat = 0;
self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING);
// Start the Cheat-Checking Cyclic Event if CheatChecking Toggleflag is on
if (toggleflags & TFLAG_CHEATCHECK)
{
te = spawn();
te.nextthink = time + 20;
te.think = TeamFortress_CheckforCheats;
te.owner = self;
te.classname = "timer";
}
if ( self.playerclass == PC_SCOUT )
{
self.items = self.items | PC_SCOUT_WEAPONS;
self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET;
self.ammo_nails = PC_SCOUT_INITAMMO_NAIL;
self.ammo_shells = PC_SCOUT_INITAMMO_SHOT;
self.ammo_cells = PC_SCOUT_INITAMMO_CELL;
self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET;
self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL;
self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT;
self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL;
self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1;
self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2;
self.tp_grenades_1 = PC_SCOUT_GRENADE_TYPE_1;
self.tp_grenades_2 = PC_SCOUT_GRENADE_TYPE_2;
self.tf_items = PC_SCOUT_TF_ITEMS;
// the scanner defaults to enemy scanning ON, friendly scanning OFF
// and movement scanner only OFF
self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
self.armorclass = self.armorclass | PC_SCOUT_INITARMORCLASS;
self.armortype = PC_SCOUT_INITARMORTYPE;
self.armorvalue = PC_SCOUT_INITARMOR;
self.armor_allowed = PC_SCOUT_MAXARMORTYPE;
self.maxarmor = PC_SCOUT_MAXARMOR;
self.weapon = IT_NAILGUN;
self.items_allowed = PC_SCOUT_WEAPONS;
}
else if ( self.playerclass == PC_SNIPER )
{
self.items = self.items | PC_SNIPER_WEAPONS;
self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET;
self.ammo_nails = PC_SNIPER_INITAMMO_NAIL;
self.ammo_shells = PC_SNIPER_INITAMMO_SHOT;
self.ammo_cells = PC_SNIPER_INITAMMO_CELL;
self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET;
self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL;
self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT;
self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL;
self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1;
self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2;
self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1;
self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2;
self.tf_items = PC_SNIPER_TF_ITEMS;
// Get the sniper's weapon
self.secondary_items = self.secondary_items | NIT_SNIPER_RIFLE | NIT_AUTO_RIFLE;
self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS;
self.armortype = PC_SNIPER_INITARMORTYPE;
self.armorvalue = PC_SNIPER_INITARMOR;
self.armor_allowed = PC_SNIPER_MAXARMORTYPE;
self.maxarmor = PC_SNIPER_MAXARMOR;
self.weapon = IT_EXTRA_WEAPON;
self.secondary_weapon = NIT_SNIPER_RIFLE;
self.items_allowed = PC_SNIPER_WEAPONS;
}
else if ( self.playerclass == PC_SOLDIER )
{
self.items = self.items | PC_SOLDIER_WEAPONS;
self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET;
self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL;
self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT;
self.ammo_cells = PC_SOLDIER_INITAMMO_CELL;
self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET;
self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL;
self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT;
self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL;
self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1;
self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2;
self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1;
self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2;
self.tf_items = PC_SOLDIER_TF_ITEMS;
self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS;
self.armortype = PC_SOLDIER_INITARMORTYPE;
self.armorvalue = PC_SOLDIER_INITARMOR;
self.armor_allowed = PC_SOLDIER_MAXARMORTYPE;
self.maxarmor = PC_SOLDIER_MAXARMOR;
self.weapon = IT_ROCKET_LAUNCHER;
self.items_allowed = PC_SOLDIER_WEAPONS;
}
else if ( self.playerclass == PC_DEMOMAN )
{
self.items = self.items | PC_DEMOMAN_WEAPONS;
self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET;
self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL;
self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT;
self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL;
self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET;
self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL;
self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT;
self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL;
self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1;
self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2;
self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1;
self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2;
self.tf_items = PC_DEMOMAN_TF_ITEMS;
// Detpacks
self.secondary_items = self.secondary_items | NIT_DETPACK;
self.ammo_detpack = PC_DEMOMAN_INITAMMO_DETPACK;
self.maxammo_detpack = PC_DEMOMAN_MAXAMMO_DETPACK;
self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS;
self.armortype = PC_DEMOMAN_INITARMORTYPE;
self.armorvalue = PC_DEMOMAN_INITARMOR;
self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE;
self.maxarmor = PC_DEMOMAN_MAXARMOR;
self.weapon = IT_GRENADE_LAUNCHER;
self.items_allowed = PC_DEMOMAN_WEAPONS;
}
else if ( self.playerclass == PC_MEDIC )
{
self.items = self.items | PC_MEDIC_WEAPONS;
self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET;
self.ammo_nails = PC_MEDIC_INITAMMO_NAIL;
self.ammo_shells = PC_MEDIC_INITAMMO_SHOT;
self.ammo_cells = PC_MEDIC_INITAMMO_CELL;
self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET;
self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL;
self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT;
self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL;
self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1;
self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2;
self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1;
self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2;
self.tf_items = PC_MEDIC_TF_ITEMS;
self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS;
self.armortype = PC_MEDIC_INITARMORTYPE;
self.armorvalue = PC_MEDIC_INITARMOR;
self.armor_allowed = PC_MEDIC_MAXARMORTYPE;
self.maxarmor = PC_MEDIC_MAXARMOR;
self.weapon = IT_SUPER_NAILGUN;
// BioWeapon
self.secondary_items = self.secondary_items | NIT_BIOWEAPON;
// Medikit
self.secondary_items = self.secondary_items | NIT_MEDIKIT;
self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT;
self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT;
// Start the Regeneration Cyclic Event
te = spawn();
te.nextthink = time + PC_MEDIC_REGEN_TIME;
te.think = TeamFortress_Regenerate;
te.owner = self;
te.classname = "timer";
self.items_allowed = PC_MEDIC_WEAPONS;
}
else if ( self.playerclass == PC_HVYWEAP )
{
self.items = self.items | PC_HVYWEAP_WEAPONS;
self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET;
self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL;
self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT;
self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL;
self.maxammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET;
self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL;
self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT;
self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL;
self.no_grenades_1 = PC_HVYWEAP_GRENADE_INIT_1;
self.no_grenades_2 = PC_HVYWEAP_GRENADE_INIT_2;
self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1;
self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2;
self.tf_items = PC_HVYWEAP_TF_ITEMS;
// Get the Assault Cannon
self.secondary_items = self.secondary_items | NIT_ASSAULT_CANNON;
self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS;
self.armortype = PC_HVYWEAP_INITARMORTYPE;
self.armorvalue = PC_HVYWEAP_INITARMOR;
self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE;
self.maxarmor = PC_HVYWEAP_MAXARMOR;
self.weapon = IT_NAILGUN;
self.items_allowed = PC_HVYWEAP_WEAPONS;
}
else if ( self.playerclass == PC_UNDEFINED )
{
self.items = 0;
self.ammo_rockets = 0;
self.ammo_nails = 0;
self.ammo_shells = 0;
self.ammo_cells = 0;
self.no_grenades_1 = 0;
self.no_grenades_2 = 0;
self.tp_grenades_1 = 0;
self.tp_grenades_2 = 0;
self.armorclass = 0;
self.armortype = 0;
self.armorvalue = 0;
self.weapon = 0;
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_NOT;
self.model = "";
self.mdl = "";
self.modelindex = 0;
modelindex_player = 0;
self.deadflag = DEAD_DEAD;
self.tfstate = self.tfstate | TFSTATE_RELOADING;
setmodel(self, "");
}
W_SetCurrentAmmo ();
};
//=========================================================================
// Return the max amount of ammo the Retriever can carry, based on his class
float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo =
{
if (AmmoType == IT_SHELLS)
{
return Retriever.maxammo_shells;
}
else if (AmmoType == IT_NAILS)
{
return Retriever.maxammo_nails;
}
else if (AmmoType == IT_CELLS)
{
return Retriever.maxammo_cells;
}
else if (AmmoType == IT_ROCKETS)
{
return Retriever.maxammo_rockets;
}
else if (AmmoType == NIT_MEDIKIT)
{
return Retriever.maxammo_medikit;
}
else if (AmmoType == NIT_DETPACK)
{
return Retriever.maxammo_detpack;
}
dprint("Error in TeamFortress_GetMaxAmmo()\n");
dprint("Invalid ammo type passed.\n");
return 0;
};
//=========================================================================
// Return 1 if the Retriever is allowed to pick up the Weapon
float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon =
{
if ( Retriever.items_allowed & WeaponType )
return 1;
return 0;
};
//=========================================================================
// Return 1 if the Retriever is allowed to pick up the Armor
float(entity Retriever, entity Armor) TeamFortress_CanGetArmor =
{
local float type;
local float af;
local string at;
if (Armor.classname == "item_armor1")
{
type = 0.3;
}
else if (Armor.classname == "item_armor2")
{
type = 0.6;
}
else if (Armor.classname == "item_armorInv")
{
type = 0.8;
}
else
{
dprint("Error in TeamFortress_CanGetArmor()\n");
dprint("Invalid armor type passed.\n");
return 0;
}
// af = Armor.spawnflags - (Armor.spawnflags & AT_NORMAL);
if ( type > Retriever.armor_allowed )
return 0;
return 1;
// if (!af)
// return 1;
// if (PC_SCOUT_ARMORCLASSES & af)
// return 1;
return 0;
};
//=========================================================================
// Controls the equipment a class receives from backpacks
float(entity Retriever, entity Items) TeamFortress_AddBackpackItems =
{
// If you want the classes to _not_ start off with all their legal
// weapons, then you may want them to be able to pick up weapons
// from backpacks. If so, this is where to do it.
// For now, return.
return;
};
//=========================================================================
// Display the name of the playerclass
void() TeamFortress_PrintClassName =
{
local string st;
if ( self.playerclass == PC_SCOUT )
sprint(self, "Scout ");
else if ( self.playerclass == PC_SNIPER )
sprint(self, "Sniper ");
else if ( self.playerclass == PC_SOLDIER )
sprint(self, "Soldier ");
else if ( self.playerclass == PC_DEMOMAN )
sprint(self, "Demolitions Man ");
else if ( self.playerclass == PC_MEDIC )
sprint(self, "Combat Medic ");
else if ( self.playerclass == PC_HVYWEAP )
sprint(self, "Heavy Weapons Guy ");
else if ( self.playerclass == PC_UNDEFINED )
sprint(self, "Undefined ");
else
{
sprint(self, "Error! Impossible Playerclass : ");
st = ftos(self.playerclass);
sprint(self, st);
sprint(self, "\n");
return;
}
if ( self.tfstate & TFSTATE_RANDOMPC)
sprint(self, "(Random)");
sprint(self, "\n");
};
//=========================================================================
// Remove all the timers for this player
void() TeamFortress_RemoveTimers =
{
local entity te;
// Remove all the timer entities for this player
te = find(world, classname, "timer");
while (te != world)
{
if (te.owner == self)
{
remove(te);
te = find(world, classname, "timer");
}
else
te = find(te, classname, "timer");
}
// Drop any GoalItems
te = find (world, classname, "item_tfgoal");
while (te)
{
if (te.owner == self)
{
// Remove it from the player
tfgoalitem_RemoveFromAP(te, self, 0);
}
te = find(te, classname, "item_tfgoal");
}
stuffcmd(self, "v_idlescale 0\n");
};
//=========================================================================
// Check all stats to make sure they're good for this class
void() TeamFortress_CheckClassStats =
{
// Check armor
if (self.armortype > self.armor_allowed)
self.armortype = self.armor_allowed;
if (self.armorvalue > self.maxarmor)
self.armorvalue = self.maxarmor;
if (self.armortype < 0)
self.armortype = 0;
if (self.armorvalue < 0)
self.armorvalue = 0;
// Check ammo
if (self.ammo_shells > TeamFortress_GetMaxAmmo(self,IT_SHELLS))
self.ammo_shells = TeamFortress_GetMaxAmmo(self,IT_SHELLS);
if (self.ammo_shells < 0)
self.ammo_shells = 0;
if (self.ammo_nails > TeamFortress_GetMaxAmmo(self,IT_NAILS))
self.ammo_nails = TeamFortress_GetMaxAmmo(self,IT_NAILS);
if (self.ammo_nails < 0)
self.ammo_nails = 0;
if (self.ammo_rockets > TeamFortress_GetMaxAmmo(self,IT_ROCKETS))
self.ammo_rockets = TeamFortress_GetMaxAmmo(self,IT_ROCKETS);
if (self.ammo_rockets < 0)
self.ammo_rockets = 0;
if (self.ammo_cells > TeamFortress_GetMaxAmmo(self,IT_CELLS))
self.ammo_cells = TeamFortress_GetMaxAmmo(self,IT_CELLS);
if (self.ammo_cells < 0)
self.ammo_cells = 0;
if (self.ammo_medikit > TeamFortress_GetMaxAmmo(self,NIT_MEDIKIT))
self.ammo_medikit = TeamFortress_GetMaxAmmo(self,NIT_MEDIKIT);
if (self.ammo_medikit < 0)
self.ammo_medikit = 0;
if (self.ammo_detpack > TeamFortress_GetMaxAmmo(self,NIT_DETPACK))
self.ammo_detpack = TeamFortress_GetMaxAmmo(self,NIT_DETPACK);
if (self.ammo_detpack < 0)
self.ammo_detpack = 0;
// Check Grenades
if (self.no_grenades_1 < 0)
self.no_grenades_1 = 0;
if (self.no_grenades_2 < 0)
self.no_grenades_2 = 0;
// Check health
if (self.health > self.max_health)
self.health = self.max_health;
if (self.health < 0)
self.health = 0;
};
//=========================================================================
// WEAPON HANDLING FUNCTIONS
//=========================================================================
//=========================================================================
// Sniper/Auto Rifle selection function
void() TeamFortress_SniperWeapon =
{
local float it;
self.impulse = 0;
if (self.tfstate & TFSTATE_RELOADING)
return;
if (!((self.secondary_items & NIT_SNIPER_RIFLE) && (self.secondary_items & NIT_AUTO_RIFLE)))
return;
if (self.ammo_shells < 1)
{ // don't have the ammo
sprint (self, "not enough ammo.\n");
return;
}
if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_SNIPER_RIFLE)
{
self.secondary_weapon = NIT_AUTO_RIFLE;
}
else if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_AUTO_RIFLE)
{
self.secondary_weapon = NIT_SNIPER_RIFLE;
}
else
{
self.secondary_weapon = NIT_SNIPER_RIFLE;
self.weapon = IT_EXTRA_WEAPON;
}
W_SetCurrentAmmo ();
};
//=========================================================================
// Assault Cannon selection function
void() TeamFortress_AssaultWeapon =
{
local float it;
self.impulse = 0;
if (self.tfstate & TFSTATE_RELOADING)
return;
if (!(self.secondary_items & NIT_ASSAULT_CANNON))
return;
if (self.heat > 0)
{
sprint(self, "the assault cannon is still overheated.\n");
return;
}
if (self.ammo_shells < 1)
{ // don't have the ammo
sprint (self, "not enough ammo.\n");
return;
}
// The cannon also nees 10 cells to power up
if (self.ammo_cells < 10)
{
sprint(self, "not enough cells to power the assault cannon.\n");
return;
}
self.secondary_weapon = NIT_ASSAULT_CANNON;
self.weapon = IT_EXTRA_WEAPON;
W_SetCurrentAmmo ();
};
//=========================================================================
// If this gets called, the players holding onto an exploding grenade :)
void() TeamFortress_ExplodePerson =
{
local entity missile;
// Removes the owners grenade
self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_GRENPRIMED);
self.owner.punchangle_x = -2;
missile = spawn ();
missile.movetype = MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
missile.classname = "grenade";
// Don't bother calculating a velocity
missile.velocity = '0 0 0';
missile.avelocity = '300 300 300';
missile.angles = vectoangles(missile.velocity);
// set the grenade's alternative kill flag
missile.tfstate = missile.tfstate | TFSTATE_ALTKILL;
// set the grenades thinktime to now
missile.nextthink = time + 0.1;
// set the think and touches to the appropriate grenade type
if (self.weapon == GR_TYPE_NORMAL)
{
missile.touch = NormalGrenadeTouch;
missile.think = NormalGrenadeExplode;
missile.altkillweapon = AK_GRENADE;
}
if (self.weapon == GR_TYPE_CONCUSSION)
{
missile.touch = ConcussionGrenadeTouch;
missile.think = ConcussionGrenadeExplode;
}
if (self.weapon == GR_TYPE_NAIL)
{
missile.touch = NailGrenadeTouch;
missile.think = NailGrenadeExplode;
missile.altkillweapon = AK_GRENADE_NAIL;
}
if (self.weapon == GR_TYPE_MIRV)
{
missile.touch = MirvGrenadeTouch;
missile.think = MirvGrenadeExplode;
missile.altkillweapon = AK_GRENADE_MIRV;
}
setmodel (missile, "progs/grenade.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.owner.origin);
bprint("No ");
bprint(self.owner.netname);
bprint(", throw the grenade, not the pin!\n");
// Remove primed grenade object
remove(self);
};
//=========================================================================
// Touch function for a concussion grenade
void() ConcussionGrenadeTouch =
{
if (other.takedamage == DAMAGE_AIM)
{
// A person hit by a concussion grenade doesn't move much,
// since their origin is pretty much right on the grenade's
// explosion point, so we'll give him a kick.
other.velocity_x = self.velocity_x - 300;
other.velocity_y = self.velocity_y - 300;
other.velocity_z = 300;
if (other.classname != "player")
{
if(other.flags & FL_ONGROUND)
other.flags = other.flags - FL_ONGROUND;
}
ConcussionGrenadeExplode();
return;
}
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
//=========================================================================
// Concussion grenade explosion function
void() ConcussionGrenadeExplode =
{
T_RadiusBounce (self, self.owner, 240, world);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
BecomeExplosion ();
};
//=========================================================================
// Concussion grenade timer to remove idlescale
void() ConcussionGrenadeTimer =
{
local string st;
self.health = self.health - GR_CONCUSS_DEC;
if (self.health < 0)
self.health = 0;
self.nextthink = time + GR_CONCUSS_TIME;
st = ftos(self.health);
stuffcmd(self.owner, "v_idlescale ");
stuffcmd(self.owner, st);
stuffcmd(self.owner, "\n");
if (self.health == 0)
remove(self);
};
//=========================================================================
// Touch Function for Nail Grenade
void() NailGrenadeTouch =
{
if (other == self.owner)
return; // don't explode on owner
// If the Nail Grenade hits a player, it just bounces off
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
//=========================================================================
// Explode Function for Nail Grenade
void() NailGrenadeExplode =
{
// Raise into the air
self.movetype = MOVETYPE_NOCLIP;
self.velocity = '0 0 100';
self.avelocity = '0 500 0';
self.nextthink = time + 0.5;
self.think = NailGrenadeNailEm;
};
//=========================================================================
// Nail function for Nail Grenade
void() NailGrenadeNailEm =
{
// Rotate and spew Nails
self.velocity = '0 0 0';
self.nextthink = time + 0.1;
self.think = NailGrenadeLaunchNail;
self.playerclass = 0;
};
//=========================================================================
// Nail function for Nail Grenade
void() NailGrenadeLaunchNail =
{
local float i,j;
i = 0;
while (i < 3)
{
j = (random() + 2) * 2;
current_yaw = anglemod( self.angles_y );
current_yaw = anglemod(current_yaw + j);
self.angles_y = current_yaw;
self.angles_x = 0;
self.angles_z = 0;
makevectors(self.angles);
launch_spike(self.origin, v_forward, 1, AK_GRENADE_NAIL);
i = i + 1;
}
self.playerclass = self.playerclass + 1;
self.nextthink = time + 0.1;
// Explode
if (self.playerclass > 50)
self.think = GrenadeExplode;
};
//=========================================================================
// Touch Function for Mirv Grenade
// Mirv Grenade heavily influenced by the Firewall Grenade by Steve Bond (wedge@nuc.net)
void() MirvGrenadeTouch =
{
if (other == self.owner)
return; // don't explode on owner
// If the Mirv Grenade hits a player, it just bounces off
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
//=========================================================================
// Mirv Grenade explode function, for when the PRIMETIME runs out
void() MirvGrenadeExplode =
{
local float i;
T_RadiusDamage (self, self.owner, 250, world);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
self.solid=SOLID_NOT;
BecomeExplosion ();
// Launch mirvs
i = 0;
while (i < GR_TYPE_MIRV_NO)
{
MirvGrenadeLaunch (self.origin + '0 0 -1',self.owner);
i = i + 1;
}
};
//=========================================================================
// Launch a Mirv
void (vector org, entity shooter) MirvGrenadeLaunch =
{
local float xdir,ydir,zdir, spin;
xdir = 150 * random() - 75;
ydir = 150 * random() - 75;
zdir = 40 * random();
newmis = spawn ();
newmis.owner = shooter;
newmis.movetype = MOVETYPE_BOUNCE;
self.touch = SUB_Null;
newmis.solid = SOLID_BBOX;
newmis.classname = "grenade";
newmis.touch = GrenadeTouch;
newmis.think = GrenadeExplode;
newmis.nextthink = time + 2;
newmis.velocity_x = xdir * 2;
newmis.velocity_y = ydir * 2;
newmis.velocity_z = zdir * 15;
// Set ALTKILL
newmis.tfstate = newmis.tfstate | TFSTATE_ALTKILL;
newmis.altkillweapon = AK_GRENADE_MIRV;
spin = (random() * 10) / 2;
if (spin <= 0)
newmis.avelocity='250 300 400';
if (spin == 1)
newmis.avelocity='400 250 300';
if (spin == 2)
newmis.avelocity='300 400 250';
if (spin == 3)
newmis.avelocity='300 300 300';
if (spin >= 4)
newmis.avelocity='400 250 400';
setmodel (newmis, "progs/grenade.mdl");
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
setorigin (newmis, org);
};
//=========================================================================
// Thrown Grenade touch function.
void() NormalGrenadeTouch =
{
if (other == self.owner)
return; // don't explode on owner
// Thrown grenades don't detonate when hitting an enemy
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
//=========================================================================
// Thrown grenade explosion. Twice as powerful as grenade launcher grenades.
void() NormalGrenadeExplode =
{
T_RadiusDamage (self, self.owner, 240, world);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
BecomeExplosion ();
};
//=========================================================================
// Detonate all thrown pipebombs
void() TeamFortress_DetonatePipebombs =
{
local entity e;
// Find all this players pipebombs
e = find(world, classname, "pipebomb");
while (e)
{
if(e.owner == self)
e.nextthink = time;
e = find(e, classname, "pipebomb");
}
};
//=========================================================================
// Pipebomb touch function
void() PipebombTouch =
{
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
//=========================================================================
// ITEM HANDLING FUNCTIONS
//=========================================================================
//=========================================================================
// Handles the scanner function for scouts, and Base Defences
void(float scanrange) TeamFortress_Scan =
{
local string power;
local entity list;
local float scen, scfr;
// added in for the direction scanner code
local float enemy_detected;
local float any_detected;
local vector vf, vr, e; // transformed versions of v_forward, v_right and the enemy vector
local float res1, res2, res3; // for the vector work
local float vf_e_angle, vr_e_angle; // results
// prevent scan impulse from triggering anything else
self.impulse = 0;
self.last_impulse = 0;
if (self.classname == "player")
{
if (!(self.tf_items & NIT_SCANNER))
return;
// If Impulse is TF_SCAN_ENEMY, toggle Scanning for Enemies
if (scanrange == TF_SCAN_ENEMY)
{
if (self.tf_items_flags & NIT_SCANNER_ENEMY)
{
sprint(self, "Enemy Scanning disabled.\n");
self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY;
return;
}
sprint(self, "Enemy Scanning enabled.\n");
self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
return;
}
// If Impulse is TF_SCAN_FRIENDLY, toggle Scanning for Friendlies
if (scanrange == TF_SCAN_FRIENDLY)
{
if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
{
sprint(self, "Friendly Scanning disabled.\n");
self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY;
return;
}
sprint(self, "Friendly Scanning enabled.\n");
self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY;
return;
}
// If the user doesn't have as many cells as he/she specified, just
// use as many as they've got.
if (scanrange > self.ammo_cells)
scanrange = self.ammo_cells;
if (scanrange <= 0)
{
sprint(self,"No cells.\n");
return;
}
if (scanrange > NIT_SCANNER_MAXCELL)
scanrange = NIT_SCANNER_MAXCELL;
scen = 0;
scfr = 0;
// Set the Scanner flags
if (self.tf_items_flags & NIT_SCANNER_ENEMY)
scen = 1;
if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
scfr = 1;
// If no entity type is enabled, don't scan
if ((scen == 0) && (scfr == 0))
{
sprint(self,"All scanner functions are disabled.\n");
return;
}
sprint(self, "Power Usage: ");
power = ftos(scanrange);
sprint(self, power);
sprint(self, ". Scanning...\n");
// Use up cells to power the scanner
// additions:
// altered this so scanner could be more easily tested
self.ammo_cells = self.ammo_cells - rint(scanrange / 5);
scanrange = scanrange * NIT_SCANNER_POWER;
// Get the list of entities the scanner finds
list = T_RadiusScan(self, scanrange, scen, scfr);
}
// Base Defence scanning code here
// Reset the entity counts
scen = 0;
scfr = 0;
// the vectors v_forward and v_right are required to
// 'triangulate' the enemies position
makevectors(self.v_angle);
// Walk the list
// For now, just count the entities.
// In the future, we'll display bearings :)
// additions: the future is now!
while (list)
{
// sets the enemy_detected flag to TRUE if not on your team, FALSE if so
any_detected = TRUE; // this flag is set to false if bogie is moving
// too slow to be detected (and velocity checking is on)
// If this scanner is a motion detector, don't record
// object that don't have the required velocity to be detected.
if (self.tf_items_flags & NIT_SCANNER_MOVEMENT)
{
if (vlen(list.velocity) > NIT_SCANNER_MIN_MOVEMENT)
{
if ((list.team > 0) && (self.team > 0) && (list.team == self.team))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else
{
any_detected = FALSE;
}
}
else
{
if ((list.team > 0) && (self.team > 0) && (list.team == self.team))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
// this displays the direction of the detected player
// using the cosine rule to find the angle
// cos theta = A.B divided by |A||B|
// it should return a value between 1 and -1
if (any_detected)
{
if (enemy_detected)
sprint(self, "Enemy detected at ");
else
sprint(self, "Comrade detected at ");
// finding the angle from v_forward gives the forward-back angle
vf = v_forward;
vf_z = 0;
// finding the angle from v_right gives the left-right angle
vr = v_right;
vr_z = 0;
// make a vector from the player to the detected one
e = list.origin - self.origin;
e_z = 0;
res1 = vlen(e);
if (res1 > 1200)
sprint(self, "very far ");
else if (res1 > 600)
sprint(self, "far ");
// dot product of vf and e (A.B)
res1 = (vf_x * e_x) + (vf_y * e_y);
// multiple the vector lengths of vf and e (eg |A||B| )
res2 = vlen(vf);
res3 = vlen(e);
res2 = res2 * res3;
// divide the results
vf_e_angle = res1 / res2;
// finding the inverse cos of this gives the angle
// but we don't need to do that because we realise:
// if res3 is 1, then the arcos would be 0 degrees (directly ahead)
// if res3 is 0.7, then the arcos would be 45 degrees (forward and off to one side)
// if res3 is 0, then the arcos would be 90 degrees (directly to the side)
// if res3 is -1, the the arcos would be 180 degrees (directly behind)
// to narrow it right down, we need to find the angle between the enemy and v_right
res1 = (vr_x * e_x) + (vr_y * e_y);
res2 = vlen(vr);
res3 = vlen(e);
res2 = res2 * res3;
vr_e_angle = res1 / res2;
// if the vr_e_angle is positive, then the enemy is on the right-hand side
// otherwise it is on the left
// if vr_e_angle is 0, then the enemy is either directly in front or behind
// the o'clock value is determined by a degree range
// eg 1 o'clock is cos 15deg to cos 45deg
// 2 o'clock is cos 45deg to cos 75deg
if (vr_e_angle > 0)
{
if (vf_e_angle >= 0.96) // cos15
sprint(self, "12");
else if (vf_e_angle >= 0.7) // cos45
sprint(self, "1");
else if (vf_e_angle >= 0.25) // cos75
sprint(self, "2");
else if (vf_e_angle >= -0.25) // cos105
sprint(self, "3");
else if (vf_e_angle >= -0.7) // cos135
sprint(self, "4");
else if (vf_e_angle >= -0.96) // cos165
sprint(self, "5");
else
sprint(self, "6");
}
else if (vr_e_angle < 0)
{
if (vf_e_angle >= 0.96)
sprint(self, "12");
else if (vf_e_angle >= 0.7)
sprint(self, "11");
else if (vf_e_angle >= 0.25)
sprint(self, "10");
else if (vf_e_angle >= -0.25)
sprint(self, "9");
else if (vf_e_angle >= -0.7)
sprint(self, "8");
else if (vf_e_angle >= -0.96)
sprint(self, "7");
else
sprint(self, "6");
}
else // vr_e_angle must be 0
{
if (vf_e_angle < 0)
sprint(self, "12");
else
sprint(self, "6");
}
sprint(self, " o'clock");
// do the up-down (z) direction
res1 = list.origin_z - self.origin_z;
if (res1 > 200)
sprint(self, ", really high");
else if (res1 > 60)
sprint(self, ", high");
else if (res1 < -200)
sprint(self, ", really low");
else if (res1 < -60)
sprint(self, ", low");
sprint(self, "\n");
} // end if(any_detected)
list = list.linked_list;
}
// Display the counts
// For Base Defences, it will display the counts to all team members
if ((scen == 0) && (scfr == 0))
{
sprint(self, "No blips.\n");
return;
}
// Update ammo levels
W_SetCurrentAmmo ();
return;
};
//=========================================================================
// Handles the Setting of Detpacks
void(float timer) TeamFortress_SetDetpack =
{
local string stimer;
local entity detp;
// prevent detpack impulse from triggering anything else
self.impulse = 0;
self.last_impulse = 0;
if (!(self.secondary_items & NIT_DETPACK))
return;
if (self.ammo_detpack <= 0)
return;
self.ammo_detpack = self.ammo_detpack - 1;
stuffcmd(self, "cl_forwardspeed 0\n");
stuffcmd(self, "cl_backspeed 0\n");
stuffcmd(self, "cl_sidespeed 0\n");
sprint(self, "Setting detpack for ");
stimer = ftos(timer);
sprint(self, stimer);
sprint(self, " seconds...\n");
detp = spawn();
detp.owner = self;
detp.classname = "timer";
detp.nextthink = time + NIT_DETPACK_SETTIME;
detp.think = TeamFortress_DetpackSet;
detp.health = timer;
};
//=========================================================================
// The detpack is set, let the player go and start timer
void() TeamFortress_DetpackSet =
{
local entity countd, dp;
TeamFortress_SetSpeed();
dp = spawn ();
dp.owner = self.owner;
dp.origin = self.owner.origin - '0 0 23';
dp.movetype = MOVETYPE_BOUNCE;
dp.solid = SOLID_TRIGGER;
dp.classname = "detpack";
dp.flags = FL_ITEM;
dp.velocity = '0 0 0';
dp.avelocity = '0 0 0';
dp.angles = vectoangles(dp.velocity);
// Set the Detpack alternative kill flag
dp.tfstate = dp.tfstate | TFSTATE_ALTKILL;
dp.altkillweapon = AK_DETPACK;
dp.touch = TeamFortress_DetpackTouch;
setmodel (dp, "progs/backpack.mdl");
setsize (dp, '-16 -16 0', '16 16 56');
setorigin (dp, self.owner.origin);
// Create the CountDown entity
countd = spawn();
countd.think = TeamFortress_DetpackCountDown;
countd.health = self.health - 1;
countd.owner = self.owner;
if (self.health <= 10)
countd.nextthink = time + 1;
else
{
countd.nextthink = time + self.health - 10;
countd.health = 9;
}
dp.nextthink = time + self.health;
dp.think = TeamFortress_DetpackExplode;
sprint(self.owner, "Detpack set!\n");
remove(self);
};
//=========================================================================
// The detpack goes BOOM!
void() TeamFortress_DetpackExplode =
{
bprint("FIRE IN THE HOLE!!!!\n");
T_RadiusDamage (self, self.owner, NIT_DETPACK_SIZE, world);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
BecomeExplosion ();
};
//=========================================================================
// The detpack touch function. Scouts can disarm it
void() TeamFortress_DetpackTouch =
{
if (other.classname != "player")
return;
if (other.playerclass != PC_SCOUT)
return;
bprint(other.netname);
bprint(" snuffs ");
bprint(self.owner.netname);
bprint("'s fuse!\n");
remove(self);
};
//=========================================================================
// The Detpack CountDown function. Displays the seconds left before the
// detpack detonates to the owner of the detpack, if <10
void() TeamFortress_DetpackCountDown =
{
local string cd;
cd = ftos(self.health);
sprint(self.owner, cd);
sprint(self.owner, "...\n");
self.nextthink = time + 1;
self.health = self.health - 1;
if (self.health == 0)
remove(self);
};
//========================================================================
// Function for handling the BioInfection Decay of players
void() BioInfection_Decay =
{
self.nextthink = time + 2;
TF_T_Damage(self.owner, self, self.enemy, 5, TF_TD_IGNOREARMOUR);
SpawnBlood(self.owner.origin, '0 0 0', 30);
// remove this entity if the infection is gone
if ( !(self.owner.tfstate & TFSTATE_INFECTED) )
remove(self);
};
//========================================================================
// Function for handling the BioInfection Decay of monsters
void() BioInfection_MonsterDecay =
{
self.nextthink = time + 2;
T_Damage(self.enemy, self, self.owner, 5);
SpawnBlood(self.enemy.origin, '0 0 0', 20);
if (self.enemy.health < 1)
remove(self);
};
//=========================================================================
// UTILITY FUNCTIONS
//=========================================================================
//=========================================================================
// Acts just like T_RadiusDamage, but doesn't damage things, just pushes them away
// from the explosion at a speed relative to the distance from the explosion's origin.
void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce =
{
local float points;
local entity head, te;
local vector org;
local string st;
head = findradius(inflictor.origin, bounce+40);
while (head)
{
if (head != ignore)
{
if (head.takedamage)
{
org = head.origin + (head.mins + head.maxs)*0.5;
points = 0.5*vlen (org - inflictor.origin);
if (points < 0)
points = 0;
points = bounce - points;
if (points > 0)
{
// Bounce!!
head.velocity = org - inflictor.origin;
head.velocity = head.velocity * (points / 10);
if (head.classname != "player")
{
if(head.flags & FL_ONGROUND)
head.flags = head.flags - FL_ONGROUND;
}
else
{
// Concuss 'em!!
// If they are already concussed, set the concussion back up
// Try to find a concusstimer entity for this player
te = find(world, classname, "timer");
while (((te.owner != head) || (te.think != ConcussionGrenadeTimer)) && (te != world))
te = find(te, classname, "timer");
if (te != world)
{
stuffcmd(head,"v_idlescale 100\n");
te.health = 100;
te.nextthink = time + GR_CONCUSS_TIME;
}
else
{
stuffcmd(head,"v_idlescale 100\n");
stuffcmd(head,"bf\n");
// Create a timer entity
te = spawn();
te.nextthink = time + GR_CONCUSS_TIME;
te.think = ConcussionGrenadeTimer;
te.classname = "timer";
te.owner = head;
te.health = 100;
}
}
}
}
}
head = head.chain;
}
};
//=========================================================================
// Returns a list of players within a radius around the origin, like findradius,
// except that some parsing of the list can be done based on the parameters passed in.
// Make sure you check that the return value is not NULL b4 using it.
entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan =
{
local entity head;
local entity list_head;
local entity list;
local float gotatarget;
head = findradius(scanner.origin, scanrange+40);
while (head)
{
gotatarget = 0;
if (head != scanner) // Don't pick up the entity that's scanning
{
if (head.takedamage)
{
if ((head.classname == "player") && (friends || enemies))
{
if (teamplay == 1)
{
if ( friends && (head.team > 0) && (scanner.team > 0) && (head.team == scanner.team) )
gotatarget = 1;
if ( enemies && (head.team > 0) && (scanner.team > 0) && (head.team != scanner.team) )
gotatarget = 1;
}
else
gotatarget = 1;
}
}
}
// Add this entity to the linked list if it matches the target criteria
if (gotatarget)
{
if (list)
{
list.linked_list = head;
list = list.linked_list;
}
else
{
list_head = head;
list = head;
}
}
head = head.chain;
}
return list_head;
};
//=========================================================================
// Stuff an alias. This is a little messy since we insisted
// on maintaining the ability to alter the impulse numbers in the defs.qc
// and not have to change any code.
void(string halias, float himpulse1, float himpulse2) TeamFortress_Alias =
{
local string imp;
stuffcmd(self, "alias ");
stuffcmd(self, halias);
stuffcmd(self, " \"impulse ");
imp = ftos(himpulse1);
stuffcmd(self, imp);
// if himpulse2 is not zero, assume that himpulse1 is a preimpulse
// and complete the alias
if (himpulse1)
{
stuffcmd(self, ";wait; impulse ");
imp = ftos(himpulse2);
stuffcmd(self, imp);
}
stuffcmd(self, "\"\n");
};
//=========================================================================
// CYCLIC EVENT FUNCTIONS
//=========================================================================
//=========================================================================
// Regenerates the entity which owns this cyclictimer
void() TeamFortress_Regenerate =
{
if (self.owner.playerclass == PC_MEDIC)
{
self.nextthink = time + PC_MEDIC_REGEN_TIME;
if (self.owner.health >= self.owner.max_health)
return;
self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT;
if (self.owner.health > self.owner.max_health)
self.owner.health = self.owner.max_health;
return;
}
return;
};
//=========================================================================
// Check for cheats :) Mainly for internet play
// This is _far_ from a good solution. It will catch non-scouts that
// set their speeds to maxspeed, but not much else.
// It will occasionally catch someone who only sets their speed up
// by a little bit.
// Still, in my opinion it was better than not checking at all.
// If anyone knows of a better way to do this, or knows how to
// get the value of a _client_ cvar, please mail me.
void() TeamFortress_CheckforCheats =
{
local float tf;
local string st;
tf = random() * 50;
self.nextthink = time + 10 + tf;
tf = vlen(self.owner.velocity);
// Since players still exceed their maxfbspeed when strafing
// as well as moving forward or backward, I played around a
// while until I decided on 300. I've never broken this.
// If you do exceed this when not cheating, please mail me.
if (tf > (self.owner.maxfbspeed + 300))
{
// Make sure they're on the ground
if ((self.owner.flags & FL_ONGROUND) && (self.velocity_z == 0))
{
bprint(self.owner.netname);
bprint(" has been fined 5 frags for cheating!\n");
self.owner.frags = self.owner.frags - 5;
T_Damage(self.owner, world, world, 400);
// Make sure they don't get fined again before they respawn
self.owner.maxfbspeed = 1000;
}
}
};